﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XSTDZ.ERP.Application.DataContracts;
using AutoMapper;
using XSTDZ.ERP.Domain.Models;
using XSTDZ.ERP.Core.Repositories;
using XSTDZ.ERP.Core.Generator;

namespace XSTDZ.ERP.Application.Implements
{
    public class ReturnBillServiceImpl : ApplicationServiceBase,IReturnBillService
    {
        IRepository<ReturnBill> _returnRepository;
        IRepository<ReturnBillDetail> _returnDetailRepository;
        IRepository<Stock> _stockRepository;
        IRepository<ProductInBill> _productRepository;
        public ReturnBillServiceImpl(IRepositoryContext repositoryContext,
            IRepository<ReturnBill> returnRepository,
            IRepository<ReturnBillDetail> returnDetailRepository,
             IRepository<ProductInBill> productRepository,
            IRepository<Stock> stockRepository)
            : base(repositoryContext)
        {
            this._returnRepository = returnRepository;
            this._returnDetailRepository = returnDetailRepository;
            this._stockRepository = stockRepository;
            this._productRepository = productRepository;
        }


        public Guid AddReturnBill(ReturnBillDto returnBillDto)
        {
            throw new NotImplementedException();
        }

        public Guid AddReturnBill(ReturnBillDto returnBillDto, IEnumerable<ReturnBillDetailDto> returnBillDetailDtos)
        {
            if (IsHasStockTooBigNum(returnBillDetailDtos)) { return Guid.Empty; }//检测是否有超过库存数量的销售单据

            var returnBill = Mapper.Map<ReturnBillDto, ReturnBill>(returnBillDto);
            var returnBillDetails = Mapper.Map<IEnumerable<ReturnBillDetailDto>, IEnumerable<ReturnBillDetail>>(returnBillDetailDtos);
            returnBillDetails.Each(t => { t.Id = (Guid)new SequentialIdentityGenerator().Next; });
            returnBill.InitReturnBill().AddDetails(returnBillDetails);
            this._returnRepository.Add(returnBill);
            this.Context.Commit();
            return returnBill.Id;
        }

        public Guid AddReturnBill(Guid returnBillId, IEnumerable<ReturnBillDetailDto> returnBillDetailDtos)
        {
            throw new NotImplementedException();
        }

        public void UpdateReturnBill(ReturnBillDto returnBillDto)
        {
            throw new NotImplementedException();
        }

        public void UpdateReturnBill(Guid returnBillId, IEnumerable<ReturnBillDetailDto> returnBillDetailDtos)
        {
            throw new NotImplementedException();
        }

        public Guid UpdateReturnBill(ReturnBillDto returnBillDto, IEnumerable<ReturnBillDetailDto> returnBillDetailDtos)
        {
            if (IsHasStockTooBigNum(returnBillDetailDtos)) { return Guid.Empty; }//检测是否有超过库存数量的销售单据

            var returnBill = this._returnRepository.GetByKey(returnBillDto.Id);
            returnBillDto.CreateTime = returnBill.CreateTime;
            var targetBill = Mapper.Map(returnBillDto, returnBill);

            //处理明细
            var productCheckBillDetails = Mapper.Map<IEnumerable<ReturnBillDetailDto>, IEnumerable<ReturnBillDetail>>(returnBillDetailDtos);

            var updateItems = new List<ReturnBillDetail>();
            var insertItems = new List<ReturnBillDetail>();
            var itemIds = returnBill.ReturnBillDetail.Select(d => d.Id).Cast<Guid>();

            productCheckBillDetails.Each(
                pd =>
                {
                    if (itemIds.Contains(pd.Id))
                    {
                        updateItems.Add(pd);
                    }
                    else
                    {
                        insertItems.Add(pd.InitReturnBillDetail());
                    }
                }
                );
            if (updateItems.Count() != 0)
            {
                foreach (var p in targetBill.ReturnBillDetail)
                {
                    foreach (var m in updateItems)
                    {
                        if (m.Id == p.Id)
                        {
                            p.StockID = m.StockID;
                            p.ReturnNo = m.ReturnNo;
                            p.Remarks = m.Remarks;
                            break;
                        }
                    }
                }

                Mapper.Map(updateItems, targetBill.ReturnBillDetail);
            }
            if (insertItems.Count() != 0)
            {
                this._returnDetailRepository.Add(insertItems);
            }
            this._returnRepository.Update(targetBill);
            this.Context.Commit();
            return targetBill.Id;
        }
        /// <summary>
        /// 检测是否有超过库存数量的销售单据
        /// </summary>
        /// <param name="ps"></param>
        /// <returns></returns>
        private bool IsHasStockTooBigNum(IEnumerable<ReturnBillDetailDto> ps)
        {
            if (ps != null && ps.Count() > 0)
            {
                foreach (var item in ps)
                {
                    if (item.ReturnNo <= 0 )
                    {
                        return true;
                        break;
                    }
                    if (_stockRepository.Exists(s => s.Id == item.StockID && s.StockCount < item.ReturnNo))
                    {
                        return true;
                        break;
                    }
                }
            }
            return false;
        }

       
        public void ConvertReturnBillDeleteState(Guid returnBillId)
        {
            var pbill = this._returnRepository.GetByKey(returnBillId);
            pbill.Deleted = 1;
            pbill.ReturnBillDetail.Each(d => { d.Deleted = 1; });
            this._returnRepository.Update(pbill);
            this.Context.Commit();
        }

        public void ConvertReturnBillDeleteState(Guid returnBillId, IEnumerable<Guid> returnBillDetailIds)
        {
            var pbill = this._returnRepository.GetByKey(returnBillId);
            pbill.ReturnBillDetail.Each(d =>
            {
                if (returnBillDetailIds.Contains(d.Id))
                {
                    d.Deleted = 1;
                }
            });
            this._returnRepository.Update(pbill);
            this.Context.Commit();
        }

        public ReturnBillDto GetReturnBill(Guid returnBillId)
        {
            var productCheckBill = this._returnRepository.GetByKey(returnBillId);
           // if (productCheckBill.Checkor == null) { productCheckBill.Checkor = new User(); };
            return Mapper.Map<ReturnBill, ReturnBillDto>(productCheckBill);
        }

        public IEnumerable<ReturnBillDto> GetReturnBills(int pageIndex, int pageSize)
        {
            var orderby = new OrderByParameter<ReturnBill>(m => m.CreateTime, SortOrder.Descending);
            var productCheckBills = this._returnRepository.GetAll(pageIndex, pageSize, new[] { orderby });
           // productCheckBills.Each(p => { if (p.Checkor == null) { p.Checkor = new User(); } });
            return Mapper.Map<IEnumerable<ReturnBill>, IEnumerable<ReturnBillDto>>(productCheckBills);
        }

        public void AddReturnBillDetail(Guid returnBillId, ReturnBillDetailDto productCheckBillDetailDto)
        {
            throw new NotImplementedException();
        }

        public void UpdateReturnBillDetail(Guid returnBillId, IEnumerable<ReturnBillDetailDto> returnBillDetailDtos)
        {
            throw new NotImplementedException();
        }

        public ReturnBillDetailDto GetReturnBillDetail(Guid productCheckBillDetailId)
        {
            var productCheckBill = this._returnDetailRepository.GetByKey(productCheckBillDetailId);
            return Mapper.Map<ReturnBillDetail, ReturnBillDetailDto>(productCheckBill);
        }

        public IEnumerable<ReturnBillDetailDto> GetReturnBillDetails(Guid returnBillId)
        {

            var productCheckBills = this._returnDetailRepository.GetAll(d => d.ReturnBillID == returnBillId);
            return Mapper.Map<IEnumerable<ReturnBillDetail>, IEnumerable<ReturnBillDetailDto>>(productCheckBills);
        }
      
        private void UpdateToStock(ReturnBill pbill)
        {
            var updateStocks = new List<Stock>();
            pbill.ReturnBillDetail.Each(d =>
            {
                updateStocks.Add(new Stock
                {
                    Id = d.StockID,
                    StockCount = -d.ReturnNo //退货数量
                });
            });
            if (updateStocks.Count() != 0)
            {
                StockServiceImpl stockServiceImpl = new StockServiceImpl(this.Context, this._stockRepository);
                stockServiceImpl.UpdateStockWithNoAdd(updateStocks);//更新库存
            }
        }
        private void UpdateToStockAdd(ReturnBill pbill,Guid wareHourseId)
        {
            var updateStocks = new List<Stock>();
            pbill.ReturnBillDetail.Each(d =>
            {
                updateStocks.Add(new Stock
                {
                   // Id = d.StockID,
                    ProductID=d.Stock.ProductID,
                    StorehouseID=wareHourseId,
                    StockCount = d.ReturnNo //退货数量
                });
            });
            if (updateStocks.Count() != 0)
            {
                StockServiceImpl stockServiceImpl = new StockServiceImpl(this.Context, this._stockRepository);
                stockServiceImpl.UpdateStockWithNoAdd(updateStocks);//更新库存
            }
        }

        public void UpdateToStock(Guid returnBillId, IEnumerable<Guid> profitAndLossBillDetailIds)
        {
            var updateStocks = new List<Stock>();
            var pbill = this._returnRepository.GetByKey(returnBillId);
            pbill.ReturnBillDetail.Each(d =>
            {
                if (profitAndLossBillDetailIds.Contains(d.Id))
                {
                    updateStocks.Add(new Stock
                    {
                        Id = d.StockID,
                        StockCount = d.ReturnNo //退货数量
                    });
                }
            });
            if (updateStocks.Count() != 0)
            {
                StockServiceImpl stockServiceImpl = new StockServiceImpl(this.Context, this._stockRepository);
                stockServiceImpl.UpdateStockWithNoAdd(updateStocks);//更新库存
                this.Context.Commit();
            }
        }
        //提交要更新库存
        public void Confirm(Guid returnBillId, Guid UserID)
        {
            var pbill = this._returnRepository.GetByKey(returnBillId);
            if (pbill.BillState != 1)
            {
                pbill.BillState = 1;
                pbill.UpdateID = UserID;
                pbill.UpdateDate = DateTime.Now;
               
                this._returnRepository.Update(pbill);
                UpdateToStock(pbill);//更新库存
                this.Context.Commit();
            }
        }
        //审核不更新库存
        public void Audit(Guid returnBillId, Guid UserID, string minProductInNo, int len, bool isChengDu, Guid wareHourseId)
        {
            var pbill = this._returnRepository.GetByKey(returnBillId);

            if (pbill.BillState == 1 && pbill.AffirmState==0)
            {
                pbill.AffirmorID = UserID;
                pbill.AffirmDate = DateTime.Now;
                pbill.AffirmState = 1;
                _returnRepository.Update(pbill);//更新
                if (isChengDu)//导入确认库存
                {
                    UpdateToStockAdd(pbill, wareHourseId);//更新库存
                }
                //if (!isChengDu)//导入确认库存
                //{
                //    ImportDeliveryToProductIn(returnBillId, UserID, minProductInNo, len);//生成入库记录
                //}

                this.Context.Commit();
            }
        }
        #region 导入确认后的出库单据到入库单中
        //导入确认的收货单到入库单
        private void ImportDeliveryToProductIn(Guid returnId, Guid createId, string minProductInNo, int len)
        {

            var deliveryList = this._returnRepository.GetByKey(returnId); //this._returnRepository.GetAll(t => deliveryIds.Contains(t.Id));
            var productInList = new List<ProductInBill>();
            productInList.Clear();

            bool isFirst = true;
            var item = deliveryList;
            //foreach (var item in deliveryList)
            if (item != null)
            {
                #region 转换发货单到入库单
                var proIn = new ProductInBill()
                {
                    CreateID = createId,
                    StorehouseID = item.Delivery.Storehouses.FirstOrDefault().Id,//wareHourseId,
                    ProductInBillNo = GetNextProductIn(minProductInNo, len, isFirst),
                    ProductInDate = DateTime.Now,
                    SenderID = item.SenderID,
                    EmployeeID = createId,
                    SourceOrgID = item.Storehouse.OrgID,
                    Remarks = "导入"

                };
                proIn.Init();
                #endregion
                #region 转化明细
                item.ReturnBillDetail.Each(t =>
                {
                    proIn.ProductInBillDetails.Add(new ProductInBillDetail
                    {
                        ProductID = t.Stock.ProductID ?? Guid.NewGuid(),
                        InlCount = t.ReturnNo,
                        ShelfNumber = "导入",
                        Remarks = t.Remarks
                    }.Init());
                });
                productInList.Add(proIn);
                #endregion
                isFirst = false;
            }

            #region 写入数据库
            ProductInServiceImpl proInImpl = new ProductInServiceImpl(this.Context, _productRepository, null, this._stockRepository);
            proInImpl.AddProductInBill(productInList);
            #endregion

        }
        //按顺序生成单号
        private string GetNextProductIn(string productInNo, int len, bool isMinNo)
        {
            if (isMinNo)
            {
                return productInNo;
            }
            var lastSec = productInNo.Substring(productInNo.Length - len - 1, len);
            var newSec = Convert.ToInt32(lastSec) + 1;
            return productInNo.Replace(lastSec, string.Format("{0:" + InitLastNo(len) + "}", newSec));
        }
        private string InitLastNo(int len)
        {
            string str = "";
            for (int i = 0; i < len; i++)
            {
                str += "0";
            }
            return str;
        }
        #endregion
        public string GetMaxBillNo()
        {
            var orderby = new OrderByParameter<ReturnBill>(m => m.CreateTime, SortOrder.Descending);
            var billNo = this._returnRepository.GetAll(1, 1, new[] { orderby }).FirstOrDefault();
            return billNo == null ? "" : billNo.ReturnBillNo;
        }
    }

}
